import cloneDeep from 'lodash/cloneDeep';
import isEqual from 'lodash/isEqual';
import pick from 'lodash/pick';
import omit from 'lodash/omit';

export type Update<T, K extends keyof T, V> = {
	[P in K]: V;
} &
	Omit<T, K>;

export const ObjectUtil = {
	/**
	 * @author 戴俊明 <idaijunming@163.com>
	 * @description 0 和 '' 为 true, null 和 undefined 为 false
	 * @date 2020/6/6 0:17
	 **/
	notNull: (o: unknown): boolean => {
		// eslint-disable-next-line eqeqeq
		return o != null;
	},

	has: (o: unknown, key: PropertyKey): boolean => {
		return Object.prototype.hasOwnProperty.call(o, key);
	},

	equals: <T, K extends keyof T>(a: T, b: T, ignoreKeys: K[] = []): boolean => {
		return isEqual(omit(a as any, ignoreKeys), omit(b as any, ignoreKeys));
	},

	clone: <T>(o: T): T => cloneDeep(o),

	pick: <T, K extends keyof T>(o: T, keys: K[] = []): Pick<T, K> =>
		pick(o as unknown, keys) as Pick<T, K>,

	omit: <T, K extends keyof T>(o: T, ignoreKeys: K[] = []): Omit<T, K> =>
		omit(o as any, ignoreKeys) as Omit<T, K>,

	assign: <T, K extends keyof T>(
		oldVal: T,
		newVal: T,
		ignoreKeys: K[] = []
	): Omit<T, K> => {
		let clone = cloneDeep(oldVal);
		clone = Object.assign(clone, newVal);
		for (const ignoreKey of ignoreKeys) {
			delete clone[ignoreKey];
		}
		return clone;
	},

	toJSON: (o: unknown): string => JSON.stringify(o),

	fromJSON: (json: string): any => {
		try {
			return JSON.parse(json);
		} catch (e) {
			return null;
		}
	},
};
